home *** CD-ROM | disk | FTP | other *** search
- _FILE VERIFICATION USING CRC_
- by Mark R. Nelson
-
- [LISTING ONE]
-
- /************************** Start of CRCMAN.C *************************
- * This program is used to build a list of CRC-32 values for all of files in a
- * given directory tree. After building file, program can be run later to
- * verify CRC values, giving assurance of integrity of files. To build CRC file
- * command line is: CRCMAN -b root-dir crc-file-name
- * To check list of files created, run with: CRCMAN crc-file-name
- * Should work with most 16 and 32-bit compilers under MS-DOS and UNIX. */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/stat.h>
-
- unsigned long CRCTable[ 256 ];
-
- /* To build this program under UNIX, define UNIX either on the command line or
- * by editing this file. To define it on the command line, program should be
- * built like this: cc -o crcman -DUNIX crcman.c Code in this program assumes
- * UNIX compiler is K&R variety; does away with real function prototyping. */
- #ifdef UNIX
-
- #include <varargs.h>
- #ifdef M_XENIX
- #include <sys/ndir.h>
- #else
- #include <sys/dirent.h>
- #endif /* M_XENIX */
-
- #define SEPARATOR "/"
- #define FILENAME_SIZE 81
-
- void FatalError();
- unsigned long CalculateFileCRC();
- void ProcessAllFiles();
- void BuildCRCFile();
- void CheckFiles();
- unsigned long CalculateBufferCRC();
- void BuildCRCTable();
-
- #else /* not UNIX, must be MSDOS */
- /* Most MS-DOS compilers have converged on same names for structures and
- * functions used when searching directories. Borland C implementations use a
- * variant, requiring macro definitions. Functions work in an identical manner,
- * so actual implementation of code is straightforward. Addition of MS-DOS
- * definition helps convince Zortech compiler to use same structure and
- * function names as everyone else. */
- #define MSDOS 1
- #include <stdarg.h>
- #include <dos.h>
-
- #define SEPARATOR "\\"
- #define FILENAME_SIZE FILENAME_MAX
-
- #ifdef __TURBOC__
-
- #include <dir.h>
- #define FILE_INFO struct ffblk
- #define FIND_FIRST( n, i ) findfirst( ( n ), ( i ), FA_DIREC )
- #define FIND_NEXT( info ) findnext( ( info ) )
- #define FILE_NAME( info ) ( ( info ).ff_name )
-
- #else
-
- #define FILE_INFO struct find_t
- #define FIND_FIRST( n, i ) _dos_findfirst( (n), _A_SUBDIR, (i) )
- #define FIND_NEXT( info ) _dos_findnext( ( info ) )
- #define FILE_NAME( info ) ( ( info ).name )
-
- #endif
-
- void FatalError( char *fmt, ... );
- unsigned long CalculateFileCRC( FILE *file );
- void ProcessAllFiles( char *path, FILE *crc_file );
- void BuildCRCFile( char *input_dir_name, char *crc_file_name );
- void CheckFiles( char *crc_file_name );
- unsigned long CalculateBufferCRC( unsigned int count, unsigned long crc,
- void *buffer );
- void BuildCRCTable( void );
-
- #endif /* UNIX */
-
- /* Main program checks for valid occurences of two different types of command
- * lines, and executes them if found. Otherwise, it prints out a simple
- * usage statement and exits. */
- int main( argc, argv )
- int argc;
- char *argv[];
- {
- setbuf( stdout, NULL );
- BuildCRCTable();
- if ( argc == 2 )
- CheckFiles( argv[ 1 ] );
- else if ( argc == 4 && strcmp( argv[ 1 ], "-b" ) == 0 )
- BuildCRCFile( argv[ 2 ], argv[ 3 ] );
- else {
- printf( "Usage: CRCMAN [-b input_dir] crc-file \n" );
- printf( "\n" );
- printf( "Using the -b option checks all files under the input_dir\n" );
- printf( "and appends their data to the crc-file. Otherwise, the\n" );
- printf( "program checks the CRC data of all of the files in the\n" );
- printf( "crc-file and prints the results\n" );
- return( 1 );
- }
- return( 0 );
- }
- /* Instead of performing a straightforward calculation of the 32-bit CRC using
- * a series of logical operations, program uses faster table lookup method. */
- #define CRC32_POLYNOMIAL 0xEDB88320L
-
- void BuildCRCTable()
- {
- int i;
- int j;
- unsigned long crc;
-
- for ( i = 0; i <= 255 ; i++ ) {
- crc = i;
- for ( j = 8 ; j > 0; j-- ) {
- if ( crc & 1 )
- crc = ( crc >> 1 ) ^ CRC32_POLYNOMIAL;
- else
- crc >>= 1;
- }
- CRCTable[ i ] = crc;
- }
- }
- /* Routine checks CRC values for a list of files. */
- void CheckFiles( crc_file_name )
- char *crc_file_name;
- {
- FILE *crc_file;
- FILE *test_file;
- unsigned long log_crc;
- unsigned long crc;
- char log_name[ FILENAME_SIZE ];
- int result;
-
- crc_file = fopen( crc_file_name, "r" );
- if ( crc_file == NULL )
- FatalError( "Couldn't open the log file: %s\n", crc_file_name );
- for ( ; ; ) {
- result = fscanf( crc_file, "%lx %s", &log_crc, log_name );
- if ( result < 2 )
- break;
- test_file = fopen( log_name, "rb" );
- if ( test_file != NULL ) {
- printf( "Checking %s ", log_name );
- crc = CalculateFileCRC( test_file );
- fclose( test_file );
- if ( crc != log_crc )
- printf( "Error: Expected %08lx, got %08lx\n",
- log_name, log_crc, crc );
- else
- printf( "OK\n" );
- } else
- printf( "Could not open file %s\n", log_name );
- }
- }
- /* ProcessAllFiles() scans directory. Routine also makes sure that directory
- * name passed on command line is stripped of trailing '/' or '\' character. */
- void BuildCRCFile( input_dir_name, crc_file_name )
- char *input_dir_name;
- char *crc_file_name;
- {
- char path[ FILENAME_SIZE ];
- FILE *crc_file;
-
- strcpy( path, input_dir_name );
- if ( path[ strlen( path ) - 1 ] == SEPARATOR[ 0 ] )
- path[ strlen( path ) - 1 ] = '\0';
- crc_file = fopen( crc_file_name, "w" );
- if ( crc_file == NULL )
- FatalError( "Can't open crc log file: %s\n", crc_file_name );
- ProcessAllFiles( path, crc_file );
- }
- /* This routine is responsible for actually performing the calculation of the
- * 32-bit CRC for the entire file. We precondition the CRC value with all 1's,
- * then invert every bit after the entire file has been done. This gives us a
- * CRC value that corresponds with the values calculated by PKZIP and ARJ. */
- unsigned long CalculateFileCRC( file )
- FILE *file;
- {
- unsigned long crc;
- int count;
- unsigned char buffer[ 512 ];
- int i;
-
- crc = 0xFFFFFFFFL;
- i = 0;
- for ( ; ; ) {
- count = fread( buffer, 1, 512, file );
- if ( ( i++ % 32 ) == 0 )
- putc( '.', stdout );
- if ( count == 0 )
- break;
- crc = CalculateBufferCRC( count, crc, buffer );
- }
- putc( ' ', stdout );
- return( crc ^= 0xFFFFFFFFL );
- }
- /* This is the routine that is responsible for calculating all of CRC values
- * for files in a given directory. The CRC values and file names are written
- * out to the crc_file. */
- void ProcessAllFiles( path, crc_file )
- char *path;
- FILE *crc_file;
- {
- #ifdef UNIX
- DIR *dirp;
- #ifdef M_XENIX
- struct direct *entry;
- #else
- struct dirent *entry;
- #endif /* M_XENIX */
- #define NAME entry->d_name
- #else
- FILE_INFO fileinfo;
- int done;
- #define NAME FILE_NAME( fileinfo )
- #endif
- char fullname[ FILENAME_SIZE ];
- struct stat buf;
- unsigned long crc;
- FILE *file;
-
- printf( "Searching %s\n", path );
- strcat( path, SEPARATOR );
- #ifdef UNIX
- dirp = opendir( path );
- if ( dirp == NULL )
- FatalError( "Error opening directory %s\n", path );
- entry = readdir( dirp );
- while ( entry != 0 ) {
- #else
- strcpy( fullname, path );
- strcat( fullname, "*.*" );
- done = FIND_FIRST( fullname, &fileinfo );
- while ( done == 0 ) {
- #endif
- strcpy( fullname, path );
- if ( strcmp( NAME, "." ) && strcmp( NAME, ".." ) ) {
- strcat( fullname, NAME );
- if ( stat( fullname, &buf ) == -1 )
- FatalError( "Error reading stat from file %s!\n", fullname );
- if ( buf.st_mode & S_IFDIR )
- ProcessAllFiles( fullname, crc_file );
- else {
- file = fopen( fullname, "rb" );
- if ( file != NULL ) {
- printf( "Scanning %s ", fullname );
- crc = CalculateFileCRC( file );
- putc( '\n', stdout );
- fprintf( crc_file, "%08lx %s\n", crc, fullname );
- fclose( file );
- } else
- printf( "Could not open %s!\n", fullname );
- }
- }
- #ifdef UNIX
- entry = readdir( dirp );
- #else
- done = FIND_NEXT( &fileinfo );
- #endif
- }
- }
- /* Routine calculates the CRC for a block of data using table lookup method.
- * It accepts an original value for the crc, and returns the updated value. */
- unsigned long CalculateBufferCRC( count, crc, buffer )
- unsigned int count;
- unsigned long crc;
- void *buffer;
- {
- unsigned char *p;
- unsigned long temp1;
- unsigned long temp2;
-
- p = (unsigned char*) buffer;
- while ( count-- != 0 ) {
- temp1 = ( crc >> 8 ) & 0x00FFFFFFL;
- temp2 = CRCTable[ ( (int) crc ^ *p++ ) & 0xff ];
- crc = temp1 ^ temp2;
- }
- return( crc );
- }
- /* Fatal error handler prints a formatted error message and then exits. */
- #ifdef UNIX
-
- void FatalError( va_alist )
- va_dcl
- {
- char *fmt;
- va_list argptr;
-
- va_start( argptr );
- fmt = va_arg( argptr, char * );
- #else
-
- void FatalError( char *fmt, ... )
- {
- va_list argptr;
- va_start( argptr, fmt );
- #endif
-
- printf( "Fatal error: " );
- vprintf( fmt, argptr );
- va_end( argptr );
- exit( -1 );
- }
-